# -*- coding: utf-8 -*-
from django.conf import settings
from django.db.models import signals
from requests.models import Request
from django.db.models.fields import SmallIntegerField
from requests.constants import PENDING_REQUEST, ADD_REQUEST, EDIT_REQUEST, \
    REMOVE_REQUEST, APPROVED_REQUEST, REJECTED_REQUEST
from django.utils import simplejson
from copy import deepcopy
from django.db.models import Model, Manager



DEFAULT_STATUS = getattr(settings, "REQUEST_DEFAULT_STATUS", PENDING_REQUEST)
DEFAULT_CONFIG = getattr(settings, "REQUEST_DEFAULT_CONFIG", {})

registered_models = {}

def register(model, conf=None):
    if model not in registered_models.keys():
        c = deepcopy(DEFAULT_CONFIG)
        if conf is not None:
            c.update(conf)
        base_manager = c.get('base_manager', None)
        manager_name = c.get('manager_name', 'objects')
        
        if base_manager is None:
            if hasattr(model, manager_name):
                base_manager = getattr(model, manager_name).__class__
            else:
                base_manager = Manager
        
        base_queryset = base_manager().get_query_set().__class__
                
        class RequestQuerySet(base_queryset):
            
            def _by_auth(self, auth):
                return self.extra(where=['request_auth = %s'], params=[auth])
                    
            def approved(self):
                return self._by_auth(APPROVED_REQUEST)
            
            def pending(self):
                return self._by_auth(PENDING_REQUEST)
            
            def rejected(self):
                return self._by_auth(REJECTED_REQUEST)
        
        class RequestManager(base_manager):
            use_for_related_fields = True
            
            def get_query_set(self):
                return RequestQuerySet(self.model, super(RequestManager, self).get_query_set().query)
        manager = RequestManager()
        model.add_to_class(manager_name, manager)
        model._default_manager = manager
        model.add_to_class('request_auth', SmallIntegerField(editable=False, default=DEFAULT_STATUS))
        model.add_to_class('request_add', lambda self, user, user_comment: request_add(self, user, user_comment))
        model.add_to_class('request_edit', lambda self, data, user, user_comment: request_edit(self, data, user, user_comment))
        model.add_to_class('request_remove', lambda self, data, user, user_comment: request_remove(self, user, user_comment))
        registered_models[model] = c

def request_add(obj, user, user_comment):
    assert obj.__class__ in registered_models
    obj.save()
    request = Request(
            type=ADD_REQUEST,
            status=DEFAULT_STATUS,
            content_object=obj,
            user=user,
            user_comment=user_comment,
            )
    request.save()

def request_edit(obj, data, user, user_comment):
    cls = obj.__class__
    assert cls in registered_models
    data = simplejson.dumps(data, ensure_ascii=False)
    apply_changes(obj, data)        
    obj.full_clean()
    request = Request(
            type=EDIT_REQUEST,
            status=DEFAULT_STATUS,
            content_object=obj,
            user=user,
            user_comment=user_comment,
            data=data,
            )
    request.save()

def request_remove(obj, user, user_comment):
    assert obj.__class__ in registered_models
    request = Request(
            type=REMOVE_REQUEST,
            status=DEFAULT_STATUS,
            content_object=obj,
            user=user,
            )
    request.save()
    
    
def apply_changes(obj, data):
    cls = obj.__class__
    assert cls in registered_models
    fields = registered_models.get(cls).get('fields', [])
    d = simplejson.loads(data)
    for k, v in d.iteritems():
        if k in fields or not fields:
            if hasattr(obj, '%s_id' % k):
                setattr(obj, '%s_id' % k, v)
            else:
                setattr(obj, k, v)
